package com.panfeng.xcloud.boss.provider.assets.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.panfeng.xcloud.boss.provider.assets.dao.mapper.*;
import com.panfeng.xcloud.boss.provider.assets.service.IExecuteOrderService;
import com.panfeng.xcloud.boss.provider.assets.service.exchange.IExchangeOperateService;
import com.panfeng.xcloud.boss.provider.assets.utils.OrderNoGenerate;
import com.panfeng.xcloud.boss.provider.dto.request.OperateBotReqDTO;
import com.panfeng.xcloud.boss.provider.dto.request.QuantBotDetailDTO;
import com.panfeng.xcloud.common.core.configuration.DataDictionaryConfig;
import com.panfeng.xcloud.common.core.enums.*;
import com.panfeng.xcloud.common.core.exceptions.BaseBizException;
import com.panfeng.xcloud.common.core.utils.CollectionUtils;
import com.panfeng.xcloud.common.core.utils.ConvertUtils;
import com.panfeng.xcloud.common.core.utils.KeyContactUtil;
import com.panfeng.xcloud.common.core.web.vo.OrderDetailResponseVO;
import com.panfeng.xcloud.common.core.web.vo.TradeResponseVO;
import com.panfeng.xcloud.dao.assets.entity.*;
import com.panfeng.xcloud.dao.member.entity.UserBase;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ExecuteOrderServiceImpl implements IExecuteOrderService {

    @Autowired
    private DataDictionaryConfig dataDictionaryConfig;

    @Autowired
    private UserExchangePwdMapperExt userExchangePwdMapperExt;

    @Autowired
    private CoinListMapperExt coinListMapperExt;

    @Autowired
    private WalletTransLogMapperExt walletTransLogMapperExt;

    @Autowired
    private WalletAssetsFlowMapperExt walletAssetsFlowMapperExt;

    @Autowired
    private UserWalletInfoMapperExt userWalletInfoMapperExt;

    @Autowired
    private WalletTransFlowMapperExt walletTransFlowMapperExt;

    @Autowired
    private OffsetTransFlowMapperExt offsetTransFlowMapperExt;

    @Autowired
    private CoinExchangeSetMapperExt coinExchangeSetMapperExt;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private IExchangeOperateService iExchangeOperateService;

    @Autowired
    private ProfitAndFeeDetailMapperExt profitAndFeeDetailMapperExt;

    @Autowired
    private UserBaseMapperExt userBaseMapperExt;

    @Autowired
    private RebateRecordMapperExt rebateRecordMapperExt;

    @Transactional(rollbackFor = Exception.class)
    public OrderDetailResponseVO chooseSendOrderHttp(OperateBotReqDTO operateBotReqDTO, Integer systemInnerType) {
        //下单
        TradeResponseVO tradeResponseVO = iExchangeOperateService.trade(operateBotReqDTO.getExchangeType(), operateBotReqDTO);

        //获取订单详情
        OrderDetailResponseVO orderDetail = iExchangeOperateService.getOrderDetail(operateBotReqDTO.getExchangeType(), operateBotReqDTO, tradeResponseVO);

        //先执行订单创建的更新操作，因为是市价下单立即成交，故马上执行订单成交的更新操作
        toUpdateOrderRecord(operateBotReqDTO, orderDetail, systemInnerType);

        return orderDetail;
    }

    /**
     * 卖单创建订单操作
     *
     * @param orderDetail
     * @param operateBotReqDTO
     */
    public void orderUpdateSellCreatedEventHandler(OrderDetailResponseVO orderDetail, OperateBotReqDTO operateBotReqDTO, Integer systemInnerType) {
        //加日志
        WalletTransLog walletTransLog = WalletTransLog.builder()
                .userId(operateBotReqDTO.getUserId())
                .flowOrderId(orderDetail.getNewClientOrderId())
                .exchangeOrderId(String.valueOf(orderDetail.getOrderId()))
                .logType(WalletTransLogTypeEnum.SELLORDER.getCode())
                .destinationCoin(operateBotReqDTO.getDestinationCoin())
                .sourceCoin(operateBotReqDTO.getSourceCoin())
                .direction(orderDetail.getDirection())
                .leverRate(orderDetail.getLeverRate())
                .exchangeType(operateBotReqDTO.getExchangeType())
                .holdAmount(orderDetail.getVolumeNum())
                .consumeMoney(orderDetail.getTradeTurnover())
                .currentPrice(orderDetail.getPrice())
                .note(new StringBuilder()
                        .append(KeyContactUtil.getContractCode(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin()))
                        .append(WalletTransLogNoteTypeEnum.DIRECTION.getMessage())
                        .append(operateBotReqDTO.getDirection().equals(PositionSideTypeEnum.BUY.getCode()) ? PositionSideTypeEnum.BUY.getMessage() : PositionSideTypeEnum.SELL.getMessage())
                        .append(WalletTransLogNoteTypeEnum.LEVERRATE.getMessage())
                        .append(orderDetail.getLeverRate())
                        .append(WalletTransLogNoteTypeEnum.ORDERUPDATESELLCREATEDEVENTHANDLER.getMessage())
                        .append(orderDetail.getVolumeNum().stripTrailingZeros().toPlainString())
                        .toString())
                .createTime(new Date())
                .modifyTime(new Date())
                .build();

        CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code,
                operateBotReqDTO.getDirection());
        if (null != coinList) {
            walletTransLog.setUrl(coinList.getUrl());
        }

        walletTransLogMapperExt.insertSelective(walletTransLog);
    }

    /**
     * 买单创建订单操作
     *
     * @param orderDetail
     * @param operateBotReqDTO
     */
    public void orderUpdateBuyEventHandler(OrderDetailResponseVO orderDetail, OperateBotReqDTO operateBotReqDTO, Integer systemInnerType) {
        //加日志
        WalletTransLog walletTransLog = WalletTransLog.builder()
                .userId(operateBotReqDTO.getUserId())
                .flowOrderId(orderDetail.getNewClientOrderId())
                .exchangeOrderId(String.valueOf(orderDetail.getOrderId()))
                .logType(WalletTransLogTypeEnum.BUYORDER.getCode())
                .destinationCoin(operateBotReqDTO.getDestinationCoin())
                .sourceCoin(operateBotReqDTO.getSourceCoin())
                .direction(orderDetail.getDirection())
                .leverRate(orderDetail.getLeverRate())
                .exchangeType(operateBotReqDTO.getExchangeType())
                .holdAmount(orderDetail.getVolumeNum())
                .consumeMoney(orderDetail.getTradeTurnover())
                .currentPrice(orderDetail.getPrice())
                .note(new StringBuilder()
                        .append(KeyContactUtil.getContractCode(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin()))
                        .append(WalletTransLogNoteTypeEnum.DIRECTION.getMessage())
                        .append(operateBotReqDTO.getDirection().equals(PositionSideTypeEnum.BUY.getCode()) ? PositionSideTypeEnum.BUY.getMessage() : PositionSideTypeEnum.SELL.getMessage())
                        .append(WalletTransLogNoteTypeEnum.LEVERRATE.getMessage())
                        .append(orderDetail.getLeverRate())
                        .append(WalletTransLogNoteTypeEnum.ORDERUPDATEBUYEVENTHANDLER.getMessage())
                        .append(orderDetail.getVolumeNum().stripTrailingZeros().toPlainString()).toString())
                .createTime(new Date())
                .modifyTime(new Date())
                .build();
        CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
        if (null != coinList) {
            walletTransLog.setUrl(coinList.getUrl());
        }

        walletTransLogMapperExt.insertSelective(walletTransLog);
    }

    /**
     * 卖单订单成交操作
     *
     * @param orderDetail
     * @param operateBotReqDTO
     */
    public void orderUpdateSellTradeEventHandler(OrderDetailResponseVO orderDetail, OperateBotReqDTO operateBotReqDTO, Integer systemInnerType) {
        WalletTransLog walletTransLog = WalletTransLog.builder()
                .userId(operateBotReqDTO.getUserId())
                .flowOrderId(orderDetail.getNewClientOrderId())
                .exchangeOrderId(String.valueOf(orderDetail.getOrderId()))
                .logType(WalletTransLogTypeEnum.SELLVOLUME.getCode())
                .destinationCoin(operateBotReqDTO.getDestinationCoin())
                .sourceCoin(operateBotReqDTO.getSourceCoin())
                .direction(orderDetail.getDirection())
                .leverRate(orderDetail.getLeverRate())
                .exchangeType(operateBotReqDTO.getExchangeType())
                .holdAmount(orderDetail.getTradeVolumeNum())
                .consumeMoney(orderDetail.getTradeTurnover())
                .currentPrice(orderDetail.getTradeAvgPrice())
                .note(new StringBuilder()
                        .append(KeyContactUtil.getContractCode(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin()))
                        .append(WalletTransLogNoteTypeEnum.DIRECTION.getMessage())
                        .append(operateBotReqDTO.getDirection().equals(PositionSideTypeEnum.BUY.getCode()) ? PositionSideTypeEnum.BUY.getMessage() : PositionSideTypeEnum.SELL.getMessage())
                        .append(WalletTransLogNoteTypeEnum.LEVERRATE.getMessage())
                        .append(orderDetail.getLeverRate())
                        .append(WalletTransLogNoteTypeEnum.ORDERUPDATESELLTRADEEVENTHANDLER.getMessage())
                        .append(orderDetail.getTradeVolumeNum().stripTrailingZeros().toPlainString())
                        .append(WalletTransLogNoteTypeEnum.TRADE_AVG_PRICE.getMessage())
                        .append(orderDetail.getTradeAvgPrice().stripTrailingZeros().toPlainString())
                        .toString())
                .createTime(new Date())
                .modifyTime(new Date())
                .build();

        CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
        if (null != coinList) {
            walletTransLog.setUrl(coinList.getUrl());
        }

        walletTransLogMapperExt.insertSelective(walletTransLog);

        //插入盈亏记录
        WalletAssetsFlow walletAssetsFlow = new WalletAssetsFlow();
        walletAssetsFlow.setFlowOrderId(orderDetail.getNewClientOrderId());
        walletAssetsFlow.setExchangeOrderId(String.valueOf(orderDetail.getOrderId()));
        walletAssetsFlow.setUserId(operateBotReqDTO.getUserId());
        walletAssetsFlow.setExchangeType(operateBotReqDTO.getExchangeType());
        walletAssetsFlow.setCoin(operateBotReqDTO.getDestinationCoin());
        walletAssetsFlow.setAmount(orderDetail.getRealProfit());
        walletAssetsFlow.setType(WalletAssetsFlowTypeEnum.PROFIT.getCode());
        walletAssetsFlow.setCreateTime(new Date());
        walletAssetsFlow.setNote(new StringBuilder()
                .append(operateBotReqDTO.getDirection().equals(PositionSideTypeEnum.BUY.getCode()) ? PositionSideTypeEnum.BUY.getMessage() : PositionSideTypeEnum.SELL.getMessage())
                .append(orderDetail.getLeverRate()).toString());
        walletAssetsFlowMapperExt.insertSelective(walletAssetsFlow);

        UserWalletInfo userWalletInfo = new UserWalletInfo();
        userWalletInfo.setUserId(operateBotReqDTO.getUserId());
        userWalletInfo.setCoinName(CoinTypeEnum.USDT.getCode());
        userWalletInfo.setChainName(ChainTypeEnum.TRON.getCode());
        UserWalletInfo updateOne = userWalletInfoMapperExt.selectOne(userWalletInfo);
        BigDecimal originPoint = updateOne.getPointBalance();
        updateOne.setAvaliableBalance(BigDecimal.ZERO);
        updateOne.setFrozenBalance(BigDecimal.ZERO);
        updateOne.setTodayProfit(orderDetail.getRealProfit());
        updateOne.setTotalProfit(orderDetail.getRealProfit());
        updateOne.setPointBalance(BigDecimal.ZERO);
        updateOne.setSubUserTotalProfit(BigDecimal.ZERO);

        BigDecimal deletePoint = BigDecimal.ZERO;

        //如果盈利为正,则更新点卡余额
        if (orderDetail.getRealProfit().compareTo(BigDecimal.ZERO) > 0) {
            deletePoint = orderDetail.getRealProfit().multiply(updateOne.getMyPointRatio());
            updateOne.setPointBalance(deletePoint.negate());

            calculateRebateInfo(operateBotReqDTO, orderDetail, deletePoint, originPoint, systemInnerType);
        }
        userWalletInfoMapperExt.updateUserWalletInfo(updateOne);

        //更新盈利手续费详情表,先查询是否表中有值,有的话就更新,没有就插入
        updateProfitAndFeeDetail(orderDetail, operateBotReqDTO);

        //加买卖流水记录
        WalletTransFlow transFlow = new WalletTransFlow();
        transFlow.setFlowOrderId(orderDetail.getNewClientOrderId());
        transFlow.setExchangeOrderId(String.valueOf(orderDetail.getOrderId()));
        transFlow.setDestinationCoin(operateBotReqDTO.getDestinationCoin());
        transFlow.setSourceCoin(operateBotReqDTO.getSourceCoin());
        transFlow.setDirection(orderDetail.getDirection());
        transFlow.setLeverRate(orderDetail.getLeverRate());
        transFlow.setUserId(operateBotReqDTO.getUserId());
        transFlow.setExchangeType(operateBotReqDTO.getExchangeType());
        transFlow.setAmount(orderDetail.getTradeVolumeNum());
        transFlow.setPrice(String.valueOf(orderDetail.getPrice()));
        transFlow.setCompleteAmount(orderDetail.getTradeVolumeNum());
        transFlow.setCompleteMoney(orderDetail.getTradeTurnover());
        transFlow.setCompleteAvePrice(orderDetail.getTradeAvgPrice());
        transFlow.setFee(orderDetail.getFee());
        transFlow.setTransType(operateBotReqDTO.getOperateType());
        transFlow.setProfit(orderDetail.getRealProfit());
        transFlow.setNote(SystemInnerTypeEnum.getByValue(systemInnerType).getInfo());
        transFlow.setDeletePoint(deletePoint);
        transFlow.setRestPoint(originPoint.subtract(deletePoint));
        transFlow.setCreateTime(new Date());
        transFlow.setModifyTime(new Date());

        //如果是对冲单,则插入对冲单交易记录表;其他的插入普通单交易记录表
        if (systemInnerType != SystemInnerTypeEnum.PRICE_RATE_SPEED_TOO_BIG.code && systemInnerType != SystemInnerTypeEnum.BIG_POSITION_OFF_SET.code
                && systemInnerType != SystemInnerTypeEnum.OFF_SET_STOP_PROFIT.code && systemInnerType != SystemInnerTypeEnum.OFF_SET_STOP_LOSS.code) {
            walletTransFlowMapperExt.insertSelective(transFlow);
        } else {
            OffsetTransFlow dto = ConvertUtils.convert(transFlow, OffsetTransFlow.class);
            offsetTransFlowMapperExt.insertSelective(dto);
        }
    }

    private void calculateRebateInfo(OperateBotReqDTO operateBotReqDTO, OrderDetailResponseVO orderDetail,
                                     BigDecimal deletePoint, BigDecimal originPoint, Integer systemInnerType) {
        //查出userWalletInfo表中的上级用户
        UserBase subUserBase = userBaseMapperExt.selectOne(operateBotReqDTO.getUserId());
        UserWalletInfo req = new UserWalletInfo();
        req.setUserId(subUserBase.getInviteCode());
        UserWalletInfo userWalletInfo = userWalletInfoMapperExt.selectOne(req);
        //查出字典表中的直推等级参数
        String defaultRebateLevel = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.default_rebate_level.getCode());
        List<String> list = Arrays.asList(defaultRebateLevel.split(","));
        Collections.reverse(list);
        //定义上级用户将要更新的用户等级，用户直推分成比例，用户直推总盈利
        String rebateLevel = null;
        BigDecimal rebateRatio = null;
        //将直推等级参数反过来轮询，判断上级用户的直推总盈利加本次盈利是否大于等于轮询到的等级
        //如果是则将定义的用户等级，用户直推分成比例，用户直推总盈利都更新，并且跳出循环
        //如果不是则继续循环
        BigDecimal newSubUserTotalProfit = userWalletInfo.getSubUserTotalProfit().add(orderDetail.getRealProfit());
        for (String levelConfig : list) {
            String[] split = levelConfig.split("-");
            String rebateLevelConfig = split[0];
            BigDecimal rebateRatioConfig = new BigDecimal(split[1]);
            BigDecimal subUserTotalProfitConfig = new BigDecimal(split[2]);
            if (newSubUserTotalProfit.compareTo(subUserTotalProfitConfig) >= 0) {
                rebateLevel = rebateLevelConfig;
                rebateRatio = rebateRatioConfig;
                break;
            }
        }
        //根据上级最新分成比例，将本次所扣点卡按对应比例生成分成信息插入返佣记录表中
        RebateRecord rebateRecord = new RebateRecord();
        rebateRecord.setFlowOrderId(orderDetail.getNewClientOrderId());
        rebateRecord.setExchangeOrderId(String.valueOf(orderDetail.getOrderId()));
        rebateRecord.setDestinationCoin(operateBotReqDTO.getDestinationCoin());
        rebateRecord.setSourceCoin(operateBotReqDTO.getSourceCoin());
        rebateRecord.setDirection(orderDetail.getDirection());
        rebateRecord.setLeverRate(orderDetail.getLeverRate());
        rebateRecord.setUserId(userWalletInfo.getUserId());
        rebateRecord.setSubUserId(operateBotReqDTO.getUserId());
        rebateRecord.setExchangeType(operateBotReqDTO.getExchangeType());
        rebateRecord.setAmount(orderDetail.getTradeVolumeNum());
        rebateRecord.setPrice(String.valueOf(orderDetail.getPrice()));
        rebateRecord.setCompleteAmount(orderDetail.getTradeVolumeNum());
        rebateRecord.setCompleteMoney(orderDetail.getTradeTurnover());
        rebateRecord.setCompleteAvePrice(orderDetail.getTradeAvgPrice());
        rebateRecord.setFee(orderDetail.getFee());
        rebateRecord.setTransType(operateBotReqDTO.getOperateType());
        rebateRecord.setProfit(orderDetail.getRealProfit());
        rebateRecord.setNote(SystemInnerTypeEnum.getByValue(systemInnerType).getInfo());
        rebateRecord.setDeletePoint(deletePoint);
        rebateRecord.setRestPoint(originPoint.subtract(deletePoint));
        rebateRecord.setRebateRatio(rebateRatio);
        rebateRecord.setRebateAmount(deletePoint.multiply(rebateRatio));
        rebateRecord.setGetRebate(GetRebateStatusEnum.UNSETTLED.value);
        rebateRecord.setDataStatus(DeleteStatusEnum.NORMAL.value);
        rebateRecord.setCreateTime(new Date());
        rebateRecord.setModifyTime(new Date());
        rebateRecordMapperExt.insertSelective(rebateRecord);
        //最后更新上级的userWalletInfo表的用户等级，分成比例和直推人总盈利
        req.setId(userWalletInfo.getId());
        req.setRebateLevel(rebateLevel);
        req.setRebateRatio(rebateRatio);
        req.setSubUserTotalProfit(orderDetail.getRealProfit());
        int i = userWalletInfoMapperExt.updateUserWalletInfo(req);
    }

    //买单订单成交操作
    public void orderUpdateEventHandler(OrderDetailResponseVO orderDetail, OperateBotReqDTO operateBotReqDTO, Integer systemInnerType) {
        //获取用户的交易对设置
        List<CoinExchangeSet> coinExchangeSets = coinExchangeSetMapperExt.queryCoinExchangeSetByUserIdExchangeTypeCoin(operateBotReqDTO.getUserId(), operateBotReqDTO.getExchangeType(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), operateBotReqDTO.getDirection());

        //用户如果不存在已保存的配置
        if (coinExchangeSets.size() < 1) {
            //使用默认,赋值
            CoinExchangeSet coinExchangeSet = getQuanDefaultConfig(operateBotReqDTO.getDirection());
            coinExchangeSet.setUserId(operateBotReqDTO.getUserId());
            coinExchangeSet.setDestinationCoin(operateBotReqDTO.getDestinationCoin());
            coinExchangeSet.setSourceCoin(operateBotReqDTO.getSourceCoin());
            coinExchangeSet.setExchangeType(operateBotReqDTO.getExchangeType());//
            coinExchangeSet.setCreateTime(new Date());
            coinExchangeSet.setModifyTime(new Date());
            coinExchangeSet.setMakeOrderNum(coinExchangeSet.getMakeOrderNum());
            coinExchangeSet.setAntiMakeOrderNum(coinExchangeSet.getAntiMakeOrderNum());
            coinExchangeSetMapperExt.insertSelective(coinExchangeSet);
        }

        //加日志
        WalletTransLog walletTransLog = WalletTransLog.builder()
                .userId(operateBotReqDTO.getUserId())
                .flowOrderId(orderDetail.getNewClientOrderId())
                .exchangeOrderId(String.valueOf(orderDetail.getOrderId()))
                .logType(WalletTransLogTypeEnum.BUYVOLUME.getCode())
                .destinationCoin(operateBotReqDTO.getDestinationCoin())
                .sourceCoin(operateBotReqDTO.getSourceCoin())
                .direction(orderDetail.getDirection())
                .leverRate(orderDetail.getLeverRate())
                .exchangeType(operateBotReqDTO.getExchangeType())
                .holdAmount(orderDetail.getTradeVolumeNum())
                .consumeMoney(orderDetail.getTradeTurnover())
                .currentPrice(orderDetail.getTradeAvgPrice())
                .note(new StringBuilder()
                        .append(KeyContactUtil.getContractCode(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin()))
                        .append(WalletTransLogNoteTypeEnum.DIRECTION.getMessage())
                        .append(operateBotReqDTO.getDirection().equals(PositionSideTypeEnum.BUY.getCode()) ? PositionSideTypeEnum.BUY.getMessage() : PositionSideTypeEnum.SELL.getMessage())
                        .append(WalletTransLogNoteTypeEnum.LEVERRATE.getMessage())
                        .append(orderDetail.getLeverRate())
                        .append(WalletTransLogNoteTypeEnum.ORDERUPDATEEVENTHANDLER.getMessage())
                        .append(orderDetail.getTradeAvgPrice().stripTrailingZeros().toPlainString()).toString())
                .createTime(new Date())
                .modifyTime(new Date())
                .build();
        //设置URL
        CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
        if (null != coinList) {
            walletTransLog.setUrl(coinList.getUrl());
        }
        walletTransLogMapperExt.insertSelective(walletTransLog);

        //更新盈利手续费详情表,先查询是否表中有值,有的话就更新,没有就插入
        updateProfitAndFeeDetail(orderDetail, operateBotReqDTO);

        //加买卖流水记录
        WalletTransFlow transFlow = new WalletTransFlow();
        transFlow.setFlowOrderId(orderDetail.getNewClientOrderId());
        transFlow.setExchangeOrderId(String.valueOf(orderDetail.getOrderId()));
        transFlow.setDestinationCoin(operateBotReqDTO.getDestinationCoin());
        transFlow.setSourceCoin(operateBotReqDTO.getSourceCoin());
        transFlow.setDirection(orderDetail.getDirection());
        transFlow.setLeverRate(orderDetail.getLeverRate());
        transFlow.setUserId(operateBotReqDTO.getUserId());
        transFlow.setExchangeType(operateBotReqDTO.getExchangeType());
        transFlow.setAmount(orderDetail.getVolumeNum());
        transFlow.setPrice(String.valueOf(orderDetail.getPrice()));
        transFlow.setCompleteAmount(orderDetail.getTradeVolumeNum());
        transFlow.setCompleteMoney(orderDetail.getTradeTurnover());
        transFlow.setCompleteAvePrice(orderDetail.getTradeAvgPrice());
        transFlow.setFee(orderDetail.getFee());
        transFlow.setTransType(operateBotReqDTO.getOperateType());
        QuantBotDetailDTO bot = getBot(operateBotReqDTO);
        if (systemInnerType == SystemInnerTypeEnum.ADD_OPEN.code) {
            transFlow.setCoverNum(Integer.valueOf(bot.getCurrentAddCount()) + 1);
            transFlow.setAntiCoverNum(Integer.valueOf(bot.getCurrentAntiAddCount()));
        } else if (systemInnerType == SystemInnerTypeEnum.ANTI_ADD_OPEN.code) {
            transFlow.setCoverNum(Integer.valueOf(bot.getCurrentAddCount()));
            transFlow.setAntiCoverNum(Integer.valueOf(bot.getCurrentAntiAddCount()) + 1);
        } else if (systemInnerType == SystemInnerTypeEnum.FIRST_OPEN.code) {
            transFlow.setCoverNum(0);
            transFlow.setAntiCoverNum(0);
        }
        transFlow.setNote(SystemInnerTypeEnum.getByValue(systemInnerType).getInfo());
        transFlow.setCreateTime(new Date());
        transFlow.setModifyTime(new Date());

        //如果是对冲单,则插入对冲单交易记录表;其他的插入普通单交易记录表
        if (systemInnerType != SystemInnerTypeEnum.PRICE_RATE_SPEED_TOO_BIG.code && systemInnerType != SystemInnerTypeEnum.BIG_POSITION_OFF_SET.code
                && systemInnerType != SystemInnerTypeEnum.OFF_SET_STOP_PROFIT.code && systemInnerType != SystemInnerTypeEnum.OFF_SET_STOP_LOSS.code) {
            walletTransFlowMapperExt.insertSelective(transFlow);
        } else {
            OffsetTransFlow dto = ConvertUtils.convert(transFlow, OffsetTransFlow.class);
            offsetTransFlowMapperExt.insertSelective(dto);
        }
    }

    //设置系统默认开单配置
    public CoinExchangeSet getQuanDefaultConfig(String direction) {
        CoinExchangeSet es = new CoinExchangeSet();
        es.setInitOrderPosition(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ORDER_POSITION.getCode())));
        es.setMakeOrderNum(Integer.valueOf(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_MAKE_ORDER_NUM.getCode())));
        es.setStopProfitRatio(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_STOP_PROFIT_RATIO.getCode())));
        es.setStopProfitBackRatio(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_STOP_PROFIT_BACK_RATIO.getCode())));
        es.setAddPosition1(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_1.getCode())).abs().negate());
        es.setAddPosition2(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_2.getCode())).abs().negate());
        es.setAddPosition3(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_3.getCode())).abs().negate());
        es.setAddPosition4(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_4.getCode())).abs().negate());
        es.setAddPosition5(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_5.getCode())).abs().negate());
        es.setAddPosition6(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_6.getCode())).abs().negate());
        es.setAddPosition7(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_7.getCode())).abs().negate());
        es.setAddPosition8(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_8.getCode())).abs().negate());
        es.setAddPosition9(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_9.getCode())).abs().negate());
        es.setAddPosition10(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_10.getCode())).abs().negate());
        es.setAddPosition11(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_11.getCode())).abs().negate());
        es.setAddPosition12(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_12.getCode())).abs().negate());
        es.setAddPosition13(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_13.getCode())).abs().negate());
        es.setAddPosition14(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_14.getCode())).abs().negate());
        es.setAddPosition15(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_15.getCode())).abs().negate());
        es.setAddPosition16(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_16.getCode())).abs().negate());
        es.setAddPosition17(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_17.getCode())).abs().negate());
        es.setAddPosition18(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_18.getCode())).abs().negate());
        es.setAddPosition19(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_19.getCode())).abs().negate());
        es.setAddPosition20(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_20.getCode())).abs().negate());
        es.setStopLossesRatio(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_STOP_LOSSES_RATIO.getCode())));
        es.setStopLossProfit(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_STOP_LOSS_PROFIT.getCode())));
        es.setAddPositionBackRatio(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ADD_POSITION_BACK_RATIO.getCode())));
        es.setAddPositionTimesModelSwitch(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.add_position_times_model_switch.getCode()));
        es.setAddPositionDynamicTimes(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.add_position_dynamic_times.getCode()));
        es.setAddPositionFixTimes(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.add_position_fix_times.getCode()));
        es.setAntiAddPositionTimesModelSwitch(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.anti_add_position_times_model_switch.getCode()));
        es.setAntiAddPositionDynamicTimes(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.anti_add_position_dynamic_times.getCode()));
        es.setAntiAddPositionFixTimes(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.anti_add_position_fix_times.getCode()));
        es.setStrategyType(Integer.parseInt(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_STRATEGY_TYPE.getCode())));
        es.setDirection(direction);
        es.setLeverRate(Integer.valueOf(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.default_lever_rate.getCode())));
        es.setBuyStopRate(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.buyStopRate.getCode())));
        es.setSellStopRate(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.sellStopRate.getCode())));
        es.setGetOffAddPositionNum(Integer.valueOf(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.getOffAddPositionNum.getCode())));
        es.setGetOffNeedTime(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.getOffNeedTime.getCode())));
        es.setGetOffProfitLine(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.getOffProfitLine.getCode())));
        es.setTotalStopLossNumLimitAddNum(Integer.valueOf(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.totalStopLossNumLimitAddNum.getCode())));
        es.setAntiMakeOrderNum(Integer.valueOf(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_MAKE_ORDER_NUM.getCode())));
        es.setAntiStopProfitRatio(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_STOP_PROFIT_RATIO.getCode())));
        es.setAntiAddPosition1(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_1.getCode())).abs());
        es.setAntiAddPosition2(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_2.getCode())).abs());
        es.setAntiAddPosition3(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_3.getCode())).abs());
        es.setAntiAddPosition4(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_4.getCode())).abs());
        es.setAntiAddPosition5(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_5.getCode())).abs());
        es.setAntiAddPosition6(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_6.getCode())).abs());
        es.setAntiAddPosition7(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_7.getCode())).abs());
        es.setAntiAddPosition8(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_8.getCode())).abs());
        es.setAntiAddPosition9(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_9.getCode())).abs());
        es.setAntiAddPosition10(new BigDecimal(dataDictionaryConfig.getCodeToNameMap().get(
                DataDictionaryTypeEnum.QUANT_DEFAULT_ANTI_ADD_POSITION_10.getCode())).abs());
        return es;
    }

    private void toUpdateOrderRecord(OperateBotReqDTO operateBotReqDTO, OrderDetailResponseVO orderDetail, Integer systemInnerType) {
        if (operateBotReqDTO.getOperateType() == OperateTypeEnum.SELL.getCode()) {
            //卖单创建订单操作
            orderUpdateSellCreatedEventHandler(orderDetail, operateBotReqDTO, systemInnerType);

            //卖单订单成交操作
            orderUpdateSellTradeEventHandler(orderDetail, operateBotReqDTO, systemInnerType);
        } else if (operateBotReqDTO.getOperateType() == OperateTypeEnum.BUY.getCode()) {
            //买单创建订单操作
            orderUpdateBuyEventHandler(orderDetail, operateBotReqDTO, systemInnerType);

            //买单订单成交操作
            orderUpdateEventHandler(orderDetail, operateBotReqDTO, systemInnerType);
        }
    }

    private QuantBotDetailDTO getBot(OperateBotReqDTO operateBotReqDTO) {
        String userBotKey = KeyContactUtil.getUserBotKey(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDirection(), operateBotReqDTO.getLeverRate(),
                operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin(), operateBotReqDTO.getUserId());
        String bot = stringRedisTemplate.opsForValue().get(userBotKey);
        QuantBotDetailDTO quantBotDetailDTO = JSONObject.parseObject(bot, QuantBotDetailDTO.class);
        return quantBotDetailDTO;
    }

    private void updateProfitAndFeeDetail(OrderDetailResponseVO orderDetail, OperateBotReqDTO operateBotReqDTO) {
        ProfitAndFeeDetail reqDTO = new ProfitAndFeeDetail();
        reqDTO.setUserId(operateBotReqDTO.getUserId());
        reqDTO.setExchangeType(operateBotReqDTO.getExchangeType());
        reqDTO.setDestinationCoin(operateBotReqDTO.getDestinationCoin());
        reqDTO.setSourceCoin(operateBotReqDTO.getSourceCoin());
        reqDTO.setLeverRate(operateBotReqDTO.getLeverRate());
        reqDTO.setDirection(operateBotReqDTO.getDirection());
        List<ProfitAndFeeDetail> profitAndFeeDetails = profitAndFeeDetailMapperExt.selectByProfitAndFeeDetail(reqDTO);

        if (CollectionUtils.isEmpty(profitAndFeeDetails)) {
            //没有就插入
            ProfitAndFeeDetail profitAndFeeDetail = new ProfitAndFeeDetail();
            profitAndFeeDetail.setUserId(operateBotReqDTO.getUserId());
            profitAndFeeDetail.setExchangeType(operateBotReqDTO.getExchangeType());
            profitAndFeeDetail.setDestinationCoin(operateBotReqDTO.getDestinationCoin());
            profitAndFeeDetail.setSourceCoin(operateBotReqDTO.getSourceCoin());
            profitAndFeeDetail.setLeverRate(operateBotReqDTO.getLeverRate());
            profitAndFeeDetail.setDirection(operateBotReqDTO.getDirection());
            profitAndFeeDetail.setTodayRealizedAmount(orderDetail.getRealProfit());
            profitAndFeeDetail.setTotalRealizedAmount(orderDetail.getRealProfit());
            profitAndFeeDetail.setTodayRealizedFee(orderDetail.getFee());
            profitAndFeeDetail.setTotalRealizedFee(orderDetail.getFee());
            profitAndFeeDetail.setFeeAsset(orderDetail.getFeeAsset());
            profitAndFeeDetail.setProfitAsset(CoinTypeEnum.USDT.getCode());
            profitAndFeeDetail.setCreateTime(new Date());
            profitAndFeeDetail.setModifyTime(new Date());

            profitAndFeeDetailMapperExt.insertSelective(profitAndFeeDetail);
        } else {
            //有的话就更新
            ProfitAndFeeDetail profitAndFeeDetail = profitAndFeeDetails.get(0);
            profitAndFeeDetail.setTodayRealizedAmount(profitAndFeeDetail.getTodayRealizedAmount().add(orderDetail.getRealProfit()));
            profitAndFeeDetail.setTotalRealizedAmount(profitAndFeeDetail.getTotalRealizedAmount().add(orderDetail.getRealProfit()));
            profitAndFeeDetail.setTodayRealizedFee(profitAndFeeDetail.getTodayRealizedFee().add(orderDetail.getFee()));
            profitAndFeeDetail.setTotalRealizedFee(profitAndFeeDetail.getTotalRealizedFee().add(orderDetail.getFee()));
            profitAndFeeDetail.setModifyTime(new Date());

            profitAndFeeDetailMapperExt.updateByPrimaryKeySelective(profitAndFeeDetail);
        }
    }

    public BigDecimal toSetOpenOrderAmount(OperateBotReqDTO operateBotReqDTO, BigDecimal amount) {
        if (operateBotReqDTO.getExchangeType() == ExchangeTypeEnum.OKEX.getCode()) {
            //获取当前价格
            BigDecimal appearMarketPrice = iExchangeOperateService.getAppearMarketPrice(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getUserId(),
                    operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin());
            //获取该交易对精度
            CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(),
                    operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
            //将下单金额转化为下单币数量(下单金额除以当前价格,并且保留交易对精度)
            BigDecimal divide = amount.divide(appearMarketPrice, 8, BigDecimal.ROUND_DOWN);
            //真实开单数量
            BigDecimal realAmount = (divide.divide(coinList.getContractCodeValue(), 1, BigDecimal.ROUND_DOWN));
            return realAmount;
        } else if (operateBotReqDTO.getExchangeType() == ExchangeTypeEnum.HUOBI.getCode()) {
            //获取当前价格
            BigDecimal appearMarketPrice = iExchangeOperateService.getAppearMarketPrice(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getUserId(),
                    operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin());
            //获取该交易对精度
            CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(),
                    operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
            //将下单金额转化为下单币数量(下单金额除以当前价格,并且保留交易对精度)
            BigDecimal divide = amount.divide(appearMarketPrice, 8, BigDecimal.ROUND_DOWN);
            //真实开单数量
            BigDecimal realAmount = (divide.divide(coinList.getContractCodeValue(), 0, BigDecimal.ROUND_DOWN));
            return realAmount;
        } else if (operateBotReqDTO.getExchangeType() == ExchangeTypeEnum.BINANCE.getCode()) {
            //获取当前价格
            BigDecimal appearMarketPrice = iExchangeOperateService.getAppearMarketPrice(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getUserId(),
                    operateBotReqDTO.getDestinationCoin(), operateBotReqDTO.getSourceCoin());
            //获取该交易对精度
            CoinList coinList = coinListMapperExt.queryCoinListByDestinationCoinAndSourceCoin(operateBotReqDTO.getExchangeType(), operateBotReqDTO.getDestinationCoin(),
                    operateBotReqDTO.getSourceCoin(), CoinListStatusTypeEnum.OPEN.code, operateBotReqDTO.getDirection());
            //将下单金额转化为下单币数量(下单金额除以当前价格,并且保留交易对精度)
            BigDecimal divide = amount.divide(appearMarketPrice, 8, BigDecimal.ROUND_DOWN);
            //真实开单数量
            BigDecimal realAmount = (divide.divide(coinList.getContractCodeValue(), 0, BigDecimal.ROUND_DOWN)).multiply(coinList.getContractCodeValue());
            return realAmount;
        } else {
            throw new BaseBizException(ResponseStatusEnum.EXCHANGE_TYPE_NOT_EXIST);
        }
    }

}
